﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Contracts;
using System.Diagnostics.Contracts;
using Shweet.Repository;

namespace Shweet.Engine
{
    public sealed class Writer
    {
        readonly IShweetMessages _shweetMessages;
        const int TAGLIMIT = 5;
        const int MESSAGELIMIT = 140;

        public Writer(IShweetMessages shweetMessages)
        {
            Contract.Requires(shweetMessages != null);
            _shweetMessages = shweetMessages;
        }

        public void Write(string shweetText, string user)
        {
            Contract.Requires(!String.IsNullOrEmpty(shweetText));
            Contract.Requires(shweetText.Length <= MESSAGELIMIT);
            Contract.Requires(!String.IsNullOrEmpty(user));

            Repository.Shweet shweet = new Repository.Shweet() 
            { 
                Text = shweetText, 
                Tags = GetTags(shweetText), 
                User = user 
            };

            _shweetMessages.Add(shweet);

        }

        private string[] GetTags(string message)
        {
            Contract.Requires(message != null);
            Contract.Ensures(Contract.Result<string[]>() != null);
            Contract.Ensures(Contract.Result<string[]>().All(IsValidTag));

            var tags = new List<string>();

            string[] hashedTags = message.Split('#');
            int tagCount = hashedTags.Length;

            for (int i = 1; i < tagCount; i++)  //Ignore first part of split as not a tag to the left
            {
                string tag = AddTrimmedTag(hashedTags[i]);
                if (IsTagNotEmptyAndIsNotADuplicate(tag,tags))
                {
                    tags.Add(tag);
                    if (TagLimitReached(tags))
                        break;
                }
            }
            return tags.ToArray<string>();
        }

        private static bool TagLimitReached(List<string> tags)
        {
            return tags.Count >= TAGLIMIT;
        }

        private static bool IsTagNotEmptyAndIsNotADuplicate(string suppiledTag, List<string> tags)
        {
            if (!String.IsNullOrEmpty(suppiledTag) && !tags.Contains(suppiledTag))
            {
                return true;
            }
            return false;
        }

        static string AddTrimmedTag(string hashedTag)
        {
            Contract.Requires(hashedTag != null);
            Contract.Requires(!hashedTag.Contains('#'));
            Contract.Ensures(String.IsNullOrEmpty(Contract.Result<string>()) || IsValidTag(Contract.Result<string>()));

            //split first word
            for (int firstSpace = 0; firstSpace < hashedTag.Length; firstSpace++)
            {
                if (char.IsWhiteSpace(hashedTag[firstSpace]))
                {
                    hashedTag = hashedTag.Substring(0, firstSpace);
                    break;
                }
            }
            return hashedTag.Length == 0 ? null : hashedTag;
        }

        #region Contract extensions
        [Pure]
        public static bool IsValidTag(string tag)
        {
            return
                !String.IsNullOrEmpty(tag) &&
                tag.All(c => !char.IsWhiteSpace(c) && c != '#');
        }
        #endregion
    }
}
